﻿using Bigway.Common.Models.DbModels;

namespace Bigway.Common.Services.Repositories;

public abstract class BaseCodeNameEntityRepository<TEntity>(IServiceProvider sp)
    : BaseSqliteRepository<TEntity>(sp), IBaseCodeNameEntityRepository<TEntity>
    where TEntity : BaseCodeNameEntity, new()
{
    public abstract List<TEntity> InitialEntities { get; }

    public async Task InitializeAllAsync(CancellationToken token = default)
    {
        var index = 1;
        var entities = InitialEntities;
        foreach (var entity in entities)
        {
            entity.Order = index++;
        }

        var entitiesMap = entities.ToDictionary(x => x.Id);
        var existingEntities = await GetAllAsync(token);
        var existingEntitiesMap = existingEntities.ToDictionary(x => x.Id);
        var newEntities = entities
            .Where(x => !existingEntitiesMap.ContainsKey(x.Id))
            .ToList();
        if (newEntities.Count > 0)
            await AddAllAsync(newEntities, token);

        var updatedEntities = entities
            .Where(x =>
                existingEntitiesMap.TryGetValue(x.Id, out var entity) &&
                (entity.Name != x.Name || entity.Order != x.Order))
            .ToList();
        if (updatedEntities.Count > 0)
            await UpdateAllAsync(updatedEntities, token);

        var deletedEntities = existingEntities
            .Where(x => !entitiesMap.ContainsKey(x.Id))
            .ToList();

        if (deletedEntities.Count > 0)
        {
            await DeleteAllAsync(deletedEntities, token);
        }
    }

    public Task<List<TEntity>> GetAllAsync(string systemId, string? code = null, CancellationToken token = default)
    {
        var result = InitialEntities.Where(x => x.SystemId == systemId).ToList();
        return Task.FromResult(result);
    }

    public Task<TEntity?> GetAsync(string systemId, string code, CancellationToken token = default)
    {
        var result = InitialEntities.Find(x => x.SystemId == systemId && x.Code == code);
        return Task.FromResult(result);
    }
}